﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.Xna.Framework;

namespace SpaceFight.Units.Steering
{
	class SteeringInfo
	{
		[Flags]
		public enum InfoType
		{
			Target                 = 1 <<  0,
			MaxMoveSpeed           = 1 <<  1,
			MaxAngularSpeed        = 1 <<  2,
			MaxAcceleration        = 1 <<  3,
			MaxAngularAcceleration = 1 <<  4,
			ArriveTargetRadius     = 1 <<  5,
			ArriveSlowRadius       = 1 <<  6,
			ArriveTimeToTarget     = 1 <<  7,
			AlignTargetRadius      = 1 <<  8,
			AlignSlowRadius        = 1 <<  9,
			AlignTimeToTarget      = 1 << 10,
			ModelFrontVector       = 1 << 11,
			WanderOffset           = 1 << 12,
			WanderRadius           = 1 << 13,
			WanderRate             = 1 << 14,
			WanderOrientation      = 1 << 15
		}
		public bool CheckMissingInfo(InfoType p_need)
		{
			InfoType missing = (~m_filledInTypes) & p_need;
			Debug.Assert(missing == 0,
			             "Not all needed SteeringInfo set.",
			             "Missing: "+ missing.ToString("F"));
			return missing == 0;
		}

		private InfoType m_filledInTypes = 0;

		public SBType     SteeringBehavior { get; set; }
		
		private IKinematic m_target;
		public IKinematic Target
		{
			get{ return m_target; }
			set{ Set(ref m_target, value, InfoType.Target); }
		}

		// Speed limits
		private float m_maxMoveSpeed;
		public float MaxMoveSpeed
		{
			get{return m_maxMoveSpeed;}
			set{ Set(ref m_maxMoveSpeed, value, InfoType.MaxMoveSpeed); }
		}
		private float m_maxAngularSpeed;
		public float MaxAngularSpeed
		{
			get{return m_maxAngularSpeed;}
			set{ Set(ref m_maxAngularSpeed, value, InfoType.MaxAngularSpeed); }
		}

		// Acceleration limits
		private float m_maxAcceleration;
		public float MaxAcceleration
		{
			get{return m_maxAcceleration;}
			set{ Set(ref m_maxAcceleration, value, InfoType.MaxAcceleration); }
		}
		private float m_maxAngularAcceleration;
		public float MaxAngularAcceleration
		{
			get{return m_maxAngularAcceleration;}
			set{ Set(ref m_maxAngularAcceleration, value, InfoType.MaxAngularAcceleration); }
		}

		// Arrive
		private float m_arriveTargetRadius;
		public float ArriveTargetRadius
		{
			get{return m_arriveTargetRadius;}
			set{ Set(ref m_arriveTargetRadius, value, InfoType.ArriveTargetRadius); }
		}
		private float m_arriveSlowRadius;
		public float ArriveSlowRadius
		{
			get{return m_arriveSlowRadius;}
			set{ Set(ref m_arriveSlowRadius, value, InfoType.ArriveSlowRadius); }
		}
		private float m_arriveTimeToTarget;
		public float ArriveTimeToTarget
		{
			get{return m_arriveTimeToTarget;}
			set{ Set(ref m_arriveTimeToTarget, value, InfoType.ArriveTimeToTarget); }
		}
		
		// Align
		private float m_alignTargetRadius;
		public float AlignTargetRadius
		{
			get{return m_alignTargetRadius;}
			set{ Set(ref m_alignTargetRadius, value, InfoType.AlignTargetRadius); }
		}
		private float m_alignSlowRadius;
		public float AlignSlowRadius
		{
			get{return m_alignSlowRadius;}
			set{ Set(ref m_alignSlowRadius, value, InfoType.AlignSlowRadius); }
		}
		private float m_alignTimeToTarget;
		public float AlignTimeToTarget
		{
			get{return m_alignTimeToTarget;}
			set{ Set(ref m_alignTimeToTarget, value, InfoType.AlignTimeToTarget); }
		}
		
		// front direction
		private Vector3 m_modelFrontVector;
		public Vector3 ModelFrontVector
		{
			get{return m_modelFrontVector;}
			set{ Set(ref m_modelFrontVector, value, InfoType.ModelFrontVector); }
		}
		
		//Wander
		private float m_wanderOffset;
		public float WanderOffset
		{
			get{return m_wanderOffset;}
			set{ Set(ref m_wanderOffset, value, InfoType.WanderOffset); }
		}
		private float m_wanderRadius;
		public float WanderRadius
		{
			get{return m_wanderRadius;}
			set{ Set(ref m_wanderRadius, value, InfoType.WanderRadius); }
		}
		private float m_wanderRate;
		public float WanderRate
		{
			get{return m_wanderRate;}
			set{ Set(ref m_wanderRate, value, InfoType.WanderRate); }
		}
		private Quaternion m_wanderOrientation;
		public Quaternion WanderOrientation
		{
			get{return m_wanderOrientation;}
			set{ Set(ref m_wanderOrientation, value, InfoType.WanderOrientation); }
		}
		
		void Set<T>(ref T p_member, T p_value, InfoType p_type)
		{
			if(p_value.Equals(p_member) == false)
			{
				m_filledInTypes = m_filledInTypes | p_type;
				p_member = p_value;
			}
		}
	}
}
